
import { _decorator, Component, Node, SpriteFrame, EventTouch, Sprite, SystemEvent, find, Label } from 'cc';
import { CommandType, Message, MessageType } from '../framework/Message';
import { MessageBase } from '../framework/MessageBase';
import { MessageCenter } from '../framework/MessageCenter';
import { GameData } from '../GameData';
import { Item } from '../player/Item';
import { Move } from '../player/Move';
import { Pet } from '../player/Pet';
import { Utils } from '../utils/Utils';
const { ccclass, property } = _decorator;

/**
 * Predefined variables
 * Name = Map
 * DateTime = Sat Feb 05 2022 15:06:15 GMT+0800 (China Standard Time)
 * Author = vvc_zeng
 * FileBasename = Map.ts
 * FileBasenameNoExtension = Map
 * URL = db://assets/script/map/Map.ts
 * ManualUrl = https://docs.cocos.com/creator/3.3/manual/zh/
 *
 */

@ccclass('Map')
export class Map extends MessageBase {
    static Instance: Map = null;

    // 当前地图数据 [1,4] 1 表示区域 4 表示索引4
    cur_map: number[];
    // 显示的提示信息锁定标志位
    show_tips_lock: boolean = false;
    // 当前地图层数
    cur_map_floor: number;
    // 当前英雄在地图的位置索引 0~35
    cur_hero_pos: number;
    // 当前游戏移动的回合数
    cur_map_turn: number;

    @property(SpriteFrame)
    goneSprite: SpriteFrame;
    // 地图的顶部提示栏节点
    tips: Node;
    onLoad() {
        super.onLoad()
        Map.Instance = this;
        this.tips = find("MainScreen/Tips");
    }
    init() {
        this.messageType = MessageType.TYPE_MAP;
    }
    initData() {
        this.cur_map = [];
        this.cur_map_floor = -1;
        this.cur_hero_pos = -1;
        this.cur_map_turn = 0;
        // 销毁上一局生成的节点
        this.node.children.forEach(e => e.destroy());
    }
    ReveiveMessage(message: Message) {
        super.ReveiveMessage(message);
        if (message.Command == CommandType.COM_MAP_INIT) {
            // 初始化数据
            this.initData()
            // 玩家进入第0层
            this.cur_map_floor++;
            // 生成第0层地图信息
            this.genMap(this.cur_map_floor);
            // 显示第0层地图
            this.initMapFloor(this.cur_map_floor);
            // 激活地图节点
            this.node.active = true;
        } else if (message.Command == CommandType.COM_MAP_SHOWTIPS) {
            this.showTips(message.Content[0], message.Content[1], message.Content[2]);
        }
    }
    // 产生地图数据
    genMap(l) {
        let total = [];
        let cur = null, res = [], _r = [];
        if (l < 3) {
            // 获得第l层的怪物列表，放入准备池中
            for (let i = 0; i < GameData.Instance.monsterLevel[l].length; i++) {
                cur = [0, GameData.Instance.monsterLevel[l][i]]
                total.push(cur)
            }
            // 获得门以外的区域，放入准备池中
            for (let i = 0; i < GameData.Instance.areaTips.length; i++) {
                if (i == 3) {
                    // 不能随机选择传送门的位置
                    continue;
                }
                cur = [1, i]
                total.push(cur)
            }
        }
        // 只从 monster 和 area 中选取
        switch (l) {
            case 0:
                // 随机选择两个门的位置
                _r = Math.random() < 0.5 ? [14, 21] : [15, 20];
                // 依次从0到35生成地图
                for (let i = 0; i < 36; i++) {
                    if (i == _r[0] || i == _r[1]) {
                        // 循环到门的位置时，生成门
                        res.push([1, 3]);
                    } else {
                        // 从准备池中随机取一项
                        res.push(total[<number>Utils.getRandomRange(0, total.length - 1)]);
                    }
                }
                break;
            case 1:
                _r = Math.random() < 0.5 ? [0, 35] : [5, 30];
                for (let i = 0; i < 36; i++) {
                    if (i == _r[0] || i == _r[1]) {
                        res.push([1, 3]);
                    } else {
                        res.push(total[<number>Utils.getRandomRange(0, total.length - 1)]);
                    }
                }
                break;
            case 2:
                _r = Math.random() < 0.5 ? [14, 21] : [15, 20];
                for (let i = 0; i < 36; i++) {
                    if (i == _r[0] || i == _r[1]) {
                        res.push([1, 3]);
                    } else {
                        res.push(total[<number>Utils.getRandomRange(0, total.length - 1)]);
                    }
                }
                break;
            case 3:
                // 一交易港口 一营地 一个随机boss
                res.push([1, 0], [1, 16]);
                res.push([0, GameData.Instance.monsterLevel[3][<number>Utils.getRandomRange(0, GameData.Instance.monsterLevel[3].length - 1)]]);
                break;
            case 4:
                // 生成用于副本的小地图
                // 渲染2个非门类的事件块2个第1层小怪块1个小boss块1个出口地块
                res.push([0, 2], [1, 0], [0, 3], [1, 16],
                    [
                        0,
                        GameData.Instance.monsterLevel[2][<number>Utils.getRandomRange(0,
                            GameData.Instance.monsterLevel[2].length - 1)]
                    ],
                    [1, 3]);
                break;
            default:
                break;
        }
        if (l < 4) {
            // 0 1 2 三层普通地图层 3 BOSS 层
            this.cur_map = <number[]>res;
        } else {
            // 4 返回小地图数据 不赋值给大地图数据 this.cur_map
            return <number[]>res;
        }
    }
    initMapFloor(f) {
        console.log("显示第" + f + "层地图,自动显示可移动的图块");
        // 绑定事件监听函数的时候，如果传递的是函数名，则重复绑定事件时只会绑定一次，如果是匿名函数，则会多次绑定
        if (f == 0) {
            // 初始化第一层的地图 
            for (let i = 0; i < this.cur_map.length; i++) {
                // 创建节点，设置位置，设置图片帧，绑定点击事件
                const node = new Node(String(i))
                node.setPosition(-250 + (i % 6) * 100, 250 - (Math.floor(i / 6) * 100), 0)
                const sprite = node.addComponent(Sprite);
                const spriteFrame = this.cur_map[i][0] ? GameData.Instance.areaFrames[this.cur_map[i][1]] : GameData.Instance.monsterFrames[this.cur_map[i][1]];
                sprite.spriteFrame = spriteFrame;
                node.parent = this.node;
                node.layer = node.parent.layer;
                node.on(SystemEvent.EventType.TOUCH_END, this.handleClickMap, this);
                // 第一层只显示4个入口
                if (i != 0 && i != 5 && i != 30 && i != 35) {
                    node.active = false;
                }
            }
        } else if (f == 1) {
            for (let i = 0; i < this.cur_map.length; i++) {
                let _n = this.node.children[i];
                const sprite = <Sprite>(_n.getComponent("cc.Sprite"));
                const spriteFrame = this.cur_map[i][0] ? GameData.Instance.areaFrames[this.cur_map[i][1]] : GameData.Instance.monsterFrames[this.cur_map[i][1]];
                sprite.spriteFrame = spriteFrame;

                // 第二层显示4个入口
                if (i == 14 || i == 15 || i == 20 || i == 21) {
                    _n.active = true;
                } else {
                    _n.active = false;
                }
                _n.on(SystemEvent.EventType.TOUCH_END, this.handleClickMap, this);
            }
        } else if (f == 2) {
            for (let i = 0; i < this.cur_map.length; i++) {
                let _n = this.node.children[i];
                const sprite = <Sprite>(_n.getComponent("cc.Sprite"));
                const spriteFrame = this.cur_map[i][0] ? GameData.Instance.areaFrames[this.cur_map[i][1]] : GameData.Instance.monsterFrames[this.cur_map[i][1]];
                sprite.spriteFrame = spriteFrame;
                // 第三层显示4个入口
                if (i == 0 || i == 5 || i == 30 || i == 35) {
                    _n.active = true;
                } else {
                    _n.active = false;
                }
                _n.on(SystemEvent.EventType.TOUCH_END, this.handleClickMap, this);

            }
        } else if (f == 3) {
            // boss层目前只有3个地图块,只需监听这3个地图块的点击事件
            for (let i = 0; i < 36; i++) {
                let _n = this.node.children[i];
                const sprite = <Sprite>(_n.getComponent("cc.Sprite"));
                if (i < this.cur_map.length) {
                    const spriteFrame = this.cur_map[i][0] ? GameData.Instance.areaFrames[this.cur_map[i][1]] : GameData.Instance.monsterFrames[this.cur_map[i][1]];
                    sprite.spriteFrame = spriteFrame;
                    _n.on(SystemEvent.EventType.TOUCH_END, this.handleClickMap, this);
                    if (i == 0) {
                        _n.active = true;
                    }
                } else {
                    sprite.spriteFrame = null;
                    _n.off(SystemEvent.EventType.TOUCH_END, this.handleClickMap, this);
                }
            }
        } else {
            console.log("error");
        }
    }

    // 在顶部消息栏显示提示信息
    showTips(pn, i, other?) {
        if (!this.show_tips_lock) {
            this.show_tips_lock = true;
            // 两秒后解锁并消失
            let t = find("MainScreen/Tips")
            t.active = true;
            let l = <Label>t.getComponent("cc.Label")
            switch (pn) {
                case 'Stat':
                    l.string = GameData.Instance.statTips[i].toString();
                    break;
                case 'PetPanel':
                    // 宠物每次出战时自动回满hp，点击宠物头像时显示宠物八个属性信息
                    l.string = GameData.Instance.monsterData[Pet.Instance.pet[i]].b.toString();
                    break;
                case 'MovePanel':
                    l.string = GameData.Instance.moveTips[Move.Instance.move[i]].toString();
                    break;
                case 'ItemPanel':
                    l.string = GameData.Instance.itemTips[Item.Instance.itemId[i]].toString();
                    break;
                default:
                    l.string = other;
                    break;
            }
            this.scheduleOnce(() => {
                this.show_tips_lock = false;
                t.active = false;
            }, 1.5);
        }
    }
    // 游戏交互逻辑
    handleClickMap(event: EventTouch) {
        let _m = <Node>(event.target)
        // 当前点击到那个下标的图块中
        let mapIndex = Number(_m.name);
        let id = this.cur_map[mapIndex];
        console.log("handleClickMap", mapIndex, id);

        let t = this.tips
        // 第一次点时，视为玩家想查看地图信息，再点一次才会将英雄移动到该图块上
        if (!this.show_tips_lock) {
            this.show_tips_lock = true;
            // 两秒后解锁并消失

            t.active = true;
            let l = <Label>t.getComponent("cc.Label")
            switch (id[0]) {
                case 0:
                    l.string = "名称:" + GameData.Instance.monsterTips[id[1]][0] + "描述:" + GameData.Instance.monsterTips[id[1]][1] + "属性:" + GameData.Instance.monsterData[id[1]].a + "经验:" + GameData.Instance.monsterData[id[1]].e + "金币:" + GameData.Instance.monsterData[id[1]].g;
                    break;
                case 1:
                    l.string = "名称:" + GameData.Instance.areaTips[id[1]][0] + "描述:" + GameData.Instance.areaTips[id[1]][1];
                    break;
                default:
                    l.string = "未定义错误字串"
                    break;
            }
            this.scheduleOnce(() => {
                this.show_tips_lock = false;
                t.active = false;
            }, 1.5);
            return;
        }

        this.show_tips_lock = false;
        t.active = false;

        // 主地图移动回合数+1
        this.cur_map_turn++;

        if (this.cur_hero_pos > -1) {
            // 已走过的图块图片变为空白
            (<Sprite>this.node.children[this.cur_hero_pos].getComponent("cc.Sprite")).spriteFrame = null;
        }
        // 改变英雄位置
        this.cur_hero_pos = mapIndex;
        // 更新视图，用脚印图片替换当前节点的图片
        let _s = <Sprite>(_m.getComponent("cc.Sprite"))
        _s.spriteFrame = this.goneSprite;
        // 取消对当前图块的点击事件的监听，重复点当前图块不会再处理点击事件
        _m.off(SystemEvent.EventType.TOUCH_END, this.handleClickMap, this);

        if (id[0] == 0) {
            // 战斗事件
            let mid = Number(id[1])
            console.log("遭遇战斗", mid);
            MessageCenter.SendCustomMessage(MessageType.TYPE_BATTLE, CommandType.COM_BATTLE_START, mid);
        } else {
            // 区域事件
            let aid = Number(id[1])
            console.log("遭遇事件", aid);
            if (aid == 3) {
                // 如果是出口，生成新地图并进入下一层
                this.goNextFloor()
                return;
            } else {
                // 将事件引用传递给事件处理器
                MessageCenter.SendCustomMessage(MessageType.TYPE_EVENT, CommandType.COM_EVENT_START, aid);
            }
        }
        // 提示下一步可移动图块
        this.renderMapHints()
    }
    goNextFloor() {
        this.cur_map_floor++;
        console.log("进入下一层", this.cur_map_floor);
        this.genMap(this.cur_map_floor);
        // 关闭当前地图层的显示
        this.node.children.forEach(e => e.active = false);
        // 显示下一层地图中的图块
        this.initMapFloor(this.cur_map_floor);
        // 进入新的一层时，英雄的位置变回-1
        this.cur_hero_pos = -1;
    }
    renderMapHints() {
        // 在0 1 2 层时，英雄点击一个图块进行移动时，显示移动后的相邻图块
        if (this.cur_map_floor < 3) {
            // 上方能走？
            if (this.cur_hero_pos > 5) {
                // 右方能走
                if ((this.cur_hero_pos + 1) % 6 != 0) {
                    // 右上能走
                    this.node.children[this.cur_hero_pos - 5].active = true;
                    this.node.children[this.cur_hero_pos + 1].active = true;
                }
                if (this.cur_hero_pos % 6 != 0) {
                    // 左上能走
                    this.node.children[this.cur_hero_pos - 7].active = true;
                    this.node.children[this.cur_hero_pos - 1].active = true;
                }
                this.node.children[this.cur_hero_pos - 6].active = true;
            }
            if (this.cur_hero_pos < 30) {
                // 左方能走
                if (this.cur_hero_pos % 6 != 0) {
                    // 左下能走
                    this.node.children[this.cur_hero_pos + 5].active = true;
                    if (typeof this.node.children[this.cur_hero_pos - 1] == 'object') {
                        this.node.children[this.cur_hero_pos - 1].active = true;
                    }
                }
                if ((this.cur_hero_pos + 1) % 6 != 0) {
                    this.node.children[this.cur_hero_pos + 1].active = true;
                    // 右下能走
                    if (typeof this.node.children[this.cur_hero_pos + 7] == 'object') {
                        this.node.children[this.cur_hero_pos + 7].active = true;
                    }
                }
                this.node.children[this.cur_hero_pos + 6].active = true;
            }
        } else {
            // 不在 0 1 2 层，那就是在小地图或boss层，每点击一个地图块，显示右边的地图块，直至移动到倒数第2个地图块

        }
    }

}

/**
 * [1] Class member could be defined like this.
 * [2] Use `property` decorator if your want the member to be serializable.
 * [3] Your initialization goes here.
 * [4] Your update function goes here.
 *
 * Learn more about scripting: https://docs.cocos.com/creator/3.3/manual/zh/scripting/
 * Learn more about CCClass: https://docs.cocos.com/creator/3.3/manual/zh/scripting/ccclass.html
 * Learn more about life-cycle callbacks: https://docs.cocos.com/creator/3.3/manual/zh/scripting/life-cycle-callbacks.html
 */
